<template>
  <aside class="group-sidebar" :class="{ interactive: showAdd }">
    <ul class="groups">
      <li v-for="g in groupsSorted" :key="g.id" class="group-row">
        <button type="button"
                class="item glass"
                :class="{ on: g.id === modelValue, over: overId===g.id }"
                :title="g.name"
                @click="$emit('update:modelValue', g.id)"
                @contextmenu.prevent="toggleMenu(g.id)"
                @dragenter.prevent="()=>overId=g.id"
                @dragover.prevent="onDragOver($event, g.id)"
                @drop.prevent="(e)=>onDrop(e,g.id)">
          <span class="ico"><svg class="if" aria-hidden="true"><use :href="'#' + normalizeIconKey(g.icon)"></use></svg></span>
          <span class="name left">{{ g.name }}</span>
        </button>
        
        <div v-if="menuFor===g.id" class="menu" @click.stop>
          <button @click="doRename(g.id, g.name)">编辑</button>
          <button class="danger" @click="doRemove(g.id)">删除</button>
        </div>
      </li>
    </ul>
    <div class="ops">
      <button type="button" class="add glass" title="添加分类" @click="showAdd=true" style="font-size: 26px;">+</button>
    </div>

    <div v-if="showAdd" class="popover-mask" @click="closePopover"></div>
    <div v-if="showAdd" class="popover glass" @click.stop style="z-index: 99996;">
      <input class="gname" v-model="newName" placeholder="分类名称" />
      <div class="icon-grid">
        <button v-for="it in presetIcons" :key="it.key" type="button" class="icon-btn" :class="{on: it.key===selectedIcon}" @click="selectedIcon=it.key">
          <svg class="if" aria-hidden="true"><use :href="'#' + it.key"></use></svg>
        </button>
      </div>
      <button class="confirm" @click="confirmAdd">{{ editMode? '保存' : '添加分类' }}</button>
    </div>
  </aside>
</template>
<script setup lang="ts">
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
import { useBookmarks } from '../../core/store/useBookmarks';
import { useSettings } from '../../core/store/useSettings';
import { LOGD, LOGW, LOGE } from '../../../shared/log.js';

const props = defineProps<{ modelValue: string }>();
const emit = defineEmits<{ (e:'update:modelValue', v:string): void }>();
const bm = useBookmarks();
const settingsStore = useSettings();

const groupsSorted = computed(()=> (bm.groups ?? []).slice().sort((a,b)=> (a.order??0)-(b.order??0)));

const DEFAULT_ICON = 'icon-shouye-zhihui';

const presetIcons = [
  // 第一排（常用）
  { key: 'icon-shouye-zhihui' },
  { key: 'icon-shezhi' },
  { key: 'icon-sousuo' },
  { key: 'icon-network' },
  { key: 'icon-movie' },
  { key: 'icon-gengduo' },
  // 第二排
  { key: 'icon-lianjie' },
  { key: 'icon-kuaijiezhifu' },
  { key: 'icon-kaitongfuwu' },
  { key: 'icon-qianshuxieyi' },
  { key: 'icon-dianpu' },
  { key: 'icon-anquanbaozhang' },
  // 第三排
  { key: 'icon-guanzhu-zhihui' },
  { key: 'icon-dingwei' },
  { key: 'icon-loading' },
  { key: 'icon-component' },
  { key: 'icon-a-3Dhuichang' },
  { key: 'icon-disc-line' },
  // 第四排
  { key: 'icon-sound-module-fill' },
  { key: 'icon-vidicon-2-line' },
  { key: 'icon-image-2-line' },
  { key: 'icon-gamepad-line' },
  { key: 'icon-vip-crown-2-line' },
  { key: 'icon-50' },
];

const showAdd = ref(false);
const editMode = ref(false);
const editingId = ref<string>('');
const newName = ref('');
const selectedIcon = ref<string>(DEFAULT_ICON);
const menuFor = ref<string>('');
const overId = ref<string>('');
const currentDragBookmarkId = ref<string>(''); // 直接记录当前拖拽的书签ID
const dragSource = ref<'grid'|'dock'|'unknown'>('unknown');

function closeMenus(){ menuFor.value=''; }
function closePopover(){
  showAdd.value=false; editMode.value=false; editingId.value=''; newName.value='';
}

function normalizeIconKey(key?: string): string {
  if (!key) return DEFAULT_ICON;
  if (key.startsWith('icon-')) return key;
  if (key.startsWith('if:')) return `icon-${key.slice(3)}`;
  const legacyMap: Record<string, string> = {
    'home': 'shouye-zhihui',
    'star': 'vip-crown-2-line',
    'movie': 'movie',
    'game': 'gamepad-line',
    'music': 'sound-module-fill',
    'globe': 'network',
    'book': 'image-2-line',
    'camera': 'image-2-line',
    'code': 'component',
    'heart': 'anquanbaozhang',
    'chat': 'gengduo',
    'tool': 'component',
    'lab': 'a-3Dhuichang',
    'map': 'dingwei',
    'bookmark': 'lianjie',
    'cloud': 'network',
  };
  const mapped = legacyMap[key];
  return mapped ? `icon-${mapped}` : DEFAULT_ICON;
}


async function confirmAdd(){
  const name = newName.value.trim();
  if(!name){ try{ (window as any).gceToast?.('请输入分类名称'); }catch{} return; }
  try{
    if(editMode.value && editingId.value){
      await bm.updateGroup(editingId.value, { name, icon: selectedIcon.value });
      closePopover();
    }else{
      await bm.addGroup(name, selectedIcon.value);
      // 强制从存储重载，避免个别环境下状态不同步导致“其它分组书签消失”
      await bm.reload();
      closePopover();
      // 选中新分组
      const g = (bm.groups||[]).slice(-1)[0];
      if(g) emit('update:modelValue', g.id);
    }
  }catch(e){ try{ (window as any).gceToast?.('添加分类失败'); }catch{} }
}

function onDragOver(e: DragEvent, gid?: string){
  if(e && e.dataTransfer) e.dataTransfer.dropEffect = 'move';
  if(gid) overId.value = gid;
}
async function onDrop(e: DragEvent, targetGroupId: string){
  e.preventDefault();
  overId.value = '';
  
  const bookmarkId = currentDragBookmarkId.value;
  LOGD('GroupSidebar', '📥 接收到drop事件', { bookmarkId, targetGroupId });
  
  if (!bookmarkId) {
    LOGW('GroupSidebar', '⚠️ 没有获取到拖拽的书签ID');
    return;
  }
  
  try {
    const bookmark = bm.bookmarks.find(b => b.id === bookmarkId);
    if (!bookmark) {
      throw new Error(`书签不存在：ID=${bookmarkId}`);
    }
    
    // 验证目标分组
    if (targetGroupId !== 'default') {
      const targetGroup = bm.groups.find(g => g.id === targetGroupId);
      if (!targetGroup) {
        throw new Error(`目标分组不存在：ID=${targetGroupId}`);
      }
    }
    
    const currentGroupId = bookmark.groupId ?? 'default';
    if (currentGroupId === targetGroupId) {
      try { (window as any).gceToast?.(`「${bookmark.title}」已经在该分组中`); } catch {}
      return;
    }
    
    // 执行移动
    await bm.moveToGroup(bookmarkId, targetGroupId);
    // 若来源为 Dock，则自动从 Dock 取消固定
    if (dragSource.value === 'dock') {
      try { await (settingsStore as any).unpinDock?.(bookmarkId); } catch {}
    }
    
    const targetGroup = bm.groups.find(g => g.id === targetGroupId);
    const targetGroupName = targetGroup?.name || (targetGroupId === 'default' ? '未分组' : '分组');
    try { 
      (window as any).gceToast?.(`已将「${bookmark.title || '书签'}」移动到「${targetGroupName}」`); 
    } catch {}
    
  } catch (err: any) { 
    console.error('移动书签失败:', err);
    try { 
      (window as any).gceToast?.(`移动失败：${err?.message || '未知错误'}`);
    } catch {}
  }
}

function onDocClick(e: MouseEvent){
  if(!menuFor.value) return;
  const menuEls = document.querySelectorAll('.group-sidebar .menu');
  let inside = false;
  menuEls.forEach(el=>{ if(el.contains(e.target as Node)) inside = true; });
  if(!inside) closeMenus();
}

// 使用ref保存函数引用，确保内存清理
const docClickHandler = ref(onDocClick);

onMounted(()=>{ 
  document.addEventListener('click', docClickHandler.value);
  
  // 监听全局拖拽事件
  const handleDragStart = (e: any) => {
    currentDragBookmarkId.value = e?.detail?.bookmarkId || '';
    dragSource.value = (e?.detail?.source === 'dock') ? 'dock' : 'grid';
  };
  const handleDragEnd = () => {
    currentDragBookmarkId.value = '';
    dragSource.value = 'unknown';
  };
  
  window.addEventListener('bookmark-drag-start', handleDragStart);
  window.addEventListener('bookmark-drag-end', handleDragEnd);
  
  // 清理函数
  onBeforeUnmount(() => {
    window.removeEventListener('bookmark-drag-start', handleDragStart);
    window.removeEventListener('bookmark-drag-end', handleDragEnd);
  });
});

onBeforeUnmount(()=>{
  document.removeEventListener('click', docClickHandler.value);
});

function toggleMenu(id: string){ menuFor.value = menuFor.value===id ? '' : id; }
async function doRename(id: string, old: string){
  // 打开编辑弹层，预填名称与图标
  const g = (bm.groups||[]).find(x=>x.id===id);
  editingId.value = id;
  editMode.value = true;
  newName.value = (g?.name ?? old ?? '').trim();
  selectedIcon.value = normalizeIconKey(g?.icon);
  menuFor.value = '';
  showAdd.value = true;
}
async function doRemove(id: string){
  const ok = await (window as any).gceConfirm?.('确定删除该分类？当该组内有链接时会提示先转移。');
  if(!ok) return;
  try{ await bm.removeGroup(id); menuFor.value=''; }
  catch(e:any){ try{ (window as any).gceToast?.(e?.message || '删除失败'); }catch{} }
}

</script>
<style scoped>
.group-sidebar{ position:fixed; right:12px; top:0; bottom:0; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; padding:12px 6px; z-index:99980; pointer-events:auto }
.groups{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px }
.group-row{ position:relative; display:flex; align-items:center; pointer-events:auto }
.item{ width:44px; height:44px; border-radius:var(--radius); border:1px solid var(--border); background: var(--glass-dark); backdrop-filter: blur(4px); color:var(--text); cursor:pointer; display:flex; align-items:center; justify-content:center; position:relative; pointer-events:auto; transition: box-shadow .18s ease, transform .18s ease }
.item:hover{ transform: translateY(-1px); box-shadow: var(--shadow-dark) }
.item.over{ outline:2px dashed var(--primary) }
.item .name{ position:absolute; background:rgba(0,0,0,.6); backdrop-filter: blur(2px); color:#fff; padding:4px 8px; border-radius:10px; font-size:12px; opacity:1; pointer-events:none; white-space:nowrap; border:1px solid rgba(255,255,255,.12) }
.item .name.left{ left:-8px; transform: translateX(-100%); }
/* 右侧位置功能已移除 */

/* light 主题玻璃风格 */
:host-context([data-theme='light']) .item{ background: rgba(255,255,255,.85); border-color: rgba(0,0,0,.08) }
:host-context([data-theme='light']) .add{ background: rgba(255,255,255,.85); border-color: rgba(0,0,0,.08) }

/* 窄屏：仅悬停显示名称，减少拥挤 */
@media (max-width: 1100px){
  .group-sidebar:not(.show-names) .item .name{ opacity:0 }
  .group-sidebar:not(.show-names) .group-row:hover .item .name{ opacity:1 }
}
.item.on{ outline:2px solid var(--primary) }
.dot{ font-weight:600 }
.ico{ display:flex; align-items:center; justify-content:center; width:20px; height:20px }
.ico .if{ width:20px; height:20px; fill: currentColor; }
.more{ display:none }
.menu{ position:absolute; right:49px; top:50%; transform: translateY(-50%); background:var(--card); border:1px solid var(--border); border-radius:10px; padding:6px; box-shadow: var(--shadow-dark); display:flex; flex-direction:column; gap:6px; z-index: 99983; min-width:140px }
.menu button{ background:transparent; border:0; color:var(--text); padding:6px 10px; text-align:left; border-radius:8px; cursor:pointer }
.menu button:hover{ background: rgba(255,255,255,.06) }
.menu .danger{ color:#ef4444 }
.ops{ display:flex; align-items:center; justify-content:center; margin-top:10px; pointer-events:auto }
.add{ width:44px; height:44px; border-radius:var(--radius); border:1px solid var(--border); background: var(--glass-dark); backdrop-filter: blur(4px); color:var(--text); cursor:pointer; box-shadow: var(--shadow-dark) }

.popover-mask{ position:fixed; inset:0; background:rgba(0,0,0,.35); z-index:99994; pointer-events:auto }
.popover{ position:fixed; right:76px; top:50%; transform: translateY(-50%); width:260px; background: var(--glass-dark); backdrop-filter: blur(6px); border:1px solid var(--border); border-radius:var(--radius); box-shadow: var(--shadow-dark); padding:12px; pointer-events:auto; z-index:99995 }
:host-context([data-theme='light']) .popover{ background: var(--glass-light); border-color: var(--border-light) }
.gname{ display:block; width:100%; box-sizing:border-box; height:34px; border:1px solid var(--border); border-radius:10px; background:var(--bg); color:var(--text); padding:0 10px; margin-bottom:10px }
.icon-grid{ display:grid; grid-template-columns: repeat(6, 1fr); gap:6px; margin-bottom:10px }
.icon-btn{ width:32px; height:32px; border-radius:8px; border:1px solid var(--border); background:var(--card); color:var(--text); display:flex; align-items:center; justify-content:center; cursor:pointer }
.icon-btn .if{ width:18px; height:18px; fill: currentColor; }
.icon-btn.on{ outline:2px solid var(--primary) }
.confirm{ width:100%; height:34px; border-radius:8px; border:1px solid var(--border); background:var(--card); color:var(--text); cursor:pointer }
.group-sidebar.interactive{ pointer-events:auto }
</style>
